#include "bleMaster.h"
#include "appConfig.h"
#include "protocol.h"
#include "devInfo.h"
#include "comm.h"


#define DBG_LEVEL DBG_INFO
#define DBG_SECTION_NAME  "bleMaster.c"
#include <rtdbg.h>

#define BLE_MSG_CMD_POS          3
#define BLE_MSG_FIX_SIZE         6 //包头报文尾固定字节
#define BLE_MASTER_NUM           2 //蓝牙主机数量
#define BLE_CONN_OUTTIME         600//10ms单位

#define ADV_UART_NAME            "uart5"//串口5
#define BLE1_UART_NAME           "uart7"
#define BLE2_UART_NAME           "uart8"

static rt_device_t  uartADV  = RT_NULL;   //广播主机
static rt_device_t  uartBle1 = RT_NULL;   //连接主机1
static rt_device_t  uartBle2 = RT_NULL;   //连接主机2

static bleSelectDef bleSelectData[BLE_MASTER_NUM];//多个蓝牙选择定义

rt_mailbox_t mcuRxMail = RT_NULL; //mcu收到蓝牙主机的
rt_mailbox_t mcuTxMail = RT_NULL; //mcu发送给蓝牙主机的

void ble_select_init(void)
{
  int i;

  for(i = 0; i < BLE_MASTER_NUM; i++)
  {
    bleSelectData[i].isBusy = 0;
    bleSelectData[i].outtime = 0;
  }
}



rt_err_t recv_ble_mail(bleMailDef *mail,rt_int32_t timeout)
{
	rt_err_t result;
	
	result = rt_mb_recv(mcuRxMail, (rt_ubase_t *)mail, timeout);

	return result;
}



rt_err_t send_ble_mail(bleMailDef *mail)
{
	rt_err_t result;

	result = rt_mb_send(mcuTxMail, (rt_ubase_t)mail);
	if(result != RT_EOK)
	{
    LOG_E("send pc mail fail");
		rt_free(mail);
	}

	return result;
}


rt_err_t ble_recv_mail(bleMailDef *mail,rt_uint8_t *mac,bleCmdDef cmd,rt_size_t outimex2)
{
  bleMailDef *recvMail;
  
  while(outimex2--)
  {
    rt_err_t result;
    
    result = recv_ble_mail((bleMailDef *)(&recvMail),2);
    if(result == RT_EOK)
    {
      if(recvMail->msg.buf[BLE_MSG_CMD_POS] == cmd)
      {
        if(recvMail->msg.buf[1] == MCU_BLE_HEAD2)//可连接主机的报文
        {
          rt_bool_t equality;
          
          equality = mac_byte_equality(recvMail->msg.proto.boudnDevAck.mac, mac);
          if(equality == RT_TRUE)
          {
            rt_memcpy(mail,recvMail,sizeof(bleMailDef));
            rt_free(recvMail);//释放掉
            return result;
          }
          else//其他主机的报文
          {
            send_ble_mail(recvMail);
          }
        }
        else
        {
          rt_memcpy(mail,recvMail,sizeof(bleMailDef));
          rt_free(recvMail);//释放掉
          return result;
        }
      }
      else
      {
        send_ble_mail(recvMail);
      }
    }
  }
  LOG_W("recv_ble_mail outime");
  return RT_ERROR;
}



static void adv_uart_recv_msg(void)
{
    rt_uint8_t ch;
    rt_uint8_t *buf = RT_NULL;
    rt_uint8_t outTime = 100;
    rt_uint8_t pos = 0;
    rt_uint8_t recvLen = 0;

    buf = rt_calloc(1, ADV_MSG_BUF);
    RT_ASSERT(buf);

    while(outTime--)
    {
        int size;
        size =  rt_device_read(uartADV,0, &ch, 1);//读取一个字节
        if(size == 1)
        {
            buf[pos++] = ch;
            if(pos == 2)
            {
                if(buf[0] != MCU_ADV_HEAD1 || buf[1] != MCU_ADV_HEAD2)
                {
                    LOG_E("ADV uart read error!buf[0]=%x buf[1]=%x",buf[0],buf[1]);
                    break;
                }
            }
            else if(pos ==3)
            {
              recvLen = buf[2];
              if(recvLen > sizeof(bleMsgDef))//长度错误
              {
                LOG_E("bleMsgDef recvLen is ERR");
                break;
              }
            }
            if((pos == recvLen)&&(recvLen != 0))//接收完成
            {
                rt_kprintf("ADV %2d>>>",recvLen);
                show_hex_string(buf, (rt_uint16_t)recvLen);
                bleMailDef *mail;

                mail = rt_calloc(1, sizeof(*mail));
                RT_ASSERT(mail);

                rt_memcpy(mail->msg.buf, buf, recvLen);
                mail->msgLen = recvLen;
                mail->outtime = NET_RX_MSG_OUTTIME;
                mail->cmd = mail->msg.buf[MSG_CMD_POS];
                rt_err_t result = rt_mb_send(mcuRxMail, (rt_ubase_t)mail);
                if(result != RT_EOK)
                {
                  LOG_E("put mcuRxMail fail !!!!!!!!!!");
                  rt_free(mail);
                  break;
                }
                else
                {
                  break;
                }
            }

        }
        else
        {
          rt_thread_mdelay(5);
        }

    }
    rt_free(buf);
}

static void adv_master_thread(void *parameter)
{
    while (1)
    {
        adv_uart_recv_msg(); //接收扫描主机信息
        rt_thread_mdelay(2);
    }
}

static void adv_ReporotedData_process(bleMailDef *bleMail,pcMailDef *pcMail)
{
  pcMail->cmd = PC_CMD_REQPORTED_ACK; 
  pcMail->msgLen = sizeof(mcuReporotedDataDef);
  pcMail->msg.proto.mcuReport.head[0] = PROTOCOL_HEAD1;
  pcMail->msg.proto.mcuReport.head[1] = PROTOCOL_HEAD2;
  pcMail->msg.proto.mcuReport.cmd = pcMail->cmd;
  rt_memcpy(&(pcMail->msg.proto.mcuReport.mode),
            &(bleMail->msg.proto.advReport.mode),
            pcMail->msgLen-BLE_MSG_FIX_SIZE);
  pcMail->msg.proto.mcuReport.len = pcMail->msgLen;
  rt_uint16_t crc = CRC16_MODBUS(pcMail->msg.buf,pcMail->msgLen-2);
  uint16_to_str(crc, &(pcMail->msg.buf[pcMail->msgLen-2]));
}


static void mcu_recv_mail_process(void)
{
  rt_err_t result;
  bleMailDef *mail;

  result = rt_mb_recv(mcuRxMail, (rt_ubase_t *)&mail, 100);
  if(result == RT_EOK)
  {
    switch(mail->msg.buf[MSG_CMD_POS])
    {
      case ADV_CMD_REQPORTED_ACK://处理主动上报数据
      {
        pcMailDef *pcMail;

        LOG_I("ADV_CMD_REQPORTED_ACK");
        pcMail = rt_calloc(1, sizeof(*pcMail));
        RT_ASSERT(pcMail);
        
        adv_ReporotedData_process(mail,pcMail);//发送给电脑
        send_pc_mail(pcMail);
        rt_free(mail);
        break;
      }
      default:
      {
        LOG_E("this %x cmd is support");
        mail->outtime--;
        if(mail->outtime)
        {
          send_ble_mail(mail);
        }
        else
        {
          rt_free(mail);
        }
        
        rt_thread_mdelay(2);
        return ;
      }
    }
  }
}


static void adv_process_thread(void *parameter)
{
    while (1)
    {
        mcu_recv_mail_process(); //接收扫描主机信息
        rt_thread_mdelay(2);
    }
}


static rt_err_t get_msg_mac(bleMailDef *mail,rt_uint8_t *mac)
{
  switch (mail->msg.buf[BLE_MSG_CMD_POS])
  {
    case BLE_CMD_BOUNDDEV_REQ:
    {
      rt_memcpy(mac,mail->msg.proto.boundDevReq.mac,MAC_BYTE_SIZE);
      return RT_EOK;
    }
    case BLE_CMD_DEVSLEEP_REQ:
    {
      rt_memcpy(mac,mail->msg.proto.devSleepReq.mac,MAC_BYTE_SIZE);
      return RT_EEMPTY;
    }
    case BLE_CMD_DEVCAP_REQ:
    {
      rt_memcpy(mac,mail->msg.proto.devCapReq.mac,MAC_BYTE_SIZE);
      return RT_EOK;
    }
    default:
    {
      LOG_E("ble CMD %x is ERR",(mail->msg.buf[BLE_MSG_CMD_POS]));
    }
  }

  return RT_ERROR;
}

rt_bool_t mac_byte_equality(rt_uint8_t *mac1,rt_uint8_t *mac2)
{
  rt_uint8_t i;

  for(i=0;i<MAC_BYTE_SIZE;i++)
  {
    if(mac1[i] != mac2[i])
    {
      return RT_FALSE;
    }
  }

  return RT_TRUE;
}

static rt_uint8_t mac_is_blelist(rt_uint8_t *mac)
{
  rt_uint8_t i;

  for(i=0;i<BLE_MASTER_NUM;i++)//在蓝牙选择列表中查找mac
  {
    rt_bool_t result;
    
    result = mac_byte_equality(bleSelectData[i].mac,mac);
    if(result == RT_TRUE)//已经存在
    {
      return i;
    }
  }

  return BLE_MASTER_NUM;
}

static void ble_mux_send_msg(rt_uint8_t uart,bleMailDef *mail)
{
  switch (uart)
  {
    case 0:
    {
      int size;
      
      rt_kprintf("BLE1 %2d<<<",mail->msgLen);
      show_hex_string(mail->msg.buf, mail->msgLen);
      size =  rt_device_write(uartBle1,0, mail->msg.buf, mail->msgLen);
      if(size != mail->msgLen)
      {
        LOG_E("BLE1 %2d<<<",mail->msgLen);
      }
      break;
    }
    case 1:
    {
      int size;
      
      rt_kprintf("BLE2 %2d<<<",mail->msgLen);
      show_hex_string(mail->msg.buf, mail->msgLen);
      size =  rt_device_write(uartBle2,0, mail->msg.buf, mail->msgLen);
      if(size != mail->msgLen)
      {
        LOG_E("BLE2 %2d<<<",mail->msgLen);
      }
      break;      
    }
  }
}


static int get_select_pos_empty(void)
{
  int i;

  for(i=0; i<BLE_MASTER_NUM; i++)
  {
    if(bleSelectData[i].isBusy == 0)
    {
      return i;
    }
  }
  return BLE_MASTER_NUM;
}


static void ble_selsct_outtime_process(void)
{
  int i;
  
  for(i=0;i<BLE_MASTER_NUM;i++)
  {
    if(bleSelectData[i].isBusy == 1)//可以发送
    {
      bleSelectData[i].outtime--;
      if(bleSelectData[i].outtime <= 0)
      {
        LOG_W("BLE%d Exit USE",i);
        rt_memset(&bleSelectData[i],0,sizeof(bleSelectDef));
        LOG_W("bleSelectData[i].outtime=%d",bleSelectData[i].outtime);
        show_hex_string(bleSelectData[i].mac, MAC_BYTE_SIZE);

        //强制发送休眠
      }
      else 
      {
        //LOG_W("bleSelectData[i].outtime=%d",bleSelectData[i].outtime);
        //show_hex_string(bleSelectData[i].mac, MAC_BYTE_SIZE);
      }
    }
  }
}


static void ble_select_send_msg(bleMailDef *mail)
{
  rt_err_t result;
  rt_uint8_t mac[MAC_BYTE_SIZE];

  result = get_msg_mac(mail, mac);//获取报文的MAC地址
  if(result != RT_ERROR)
  {
    rt_uint8_t have;
    
    LOG_I("BLE MSG Have MAC%x:%x:%x:%x:%x:%x",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
    

    have = mac_is_blelist(mac);
    if(have < BLE_MASTER_NUM)//找到了mac
    {
       LOG_W("BLE is BLEList Dev");
       if(result == RT_EEMPTY)//准备休眠
       {
         //发送数据
         ble_mux_send_msg(have, mail);
         bleSelectData[have].isBusy = 0;
         rt_memset(bleSelectData[have].mac, 0, MAC_BYTE_SIZE);
         LOG_W("BLE is Del List");
       }
       else
       {
         ble_mux_send_msg(have, mail);
       }
    }
    else//没有在列表里面
    { 
      int pos;

      pos = get_select_pos_empty();
      if(pos < BLE_MASTER_NUM)//有空闲的主机
      {
        LOG_W("BLE%d Enter USE",pos);
        bleSelectData[pos].isBusy = 1;
        rt_memcpy(bleSelectData[pos].mac, 
                  mac, MAC_BYTE_SIZE);
        bleSelectData[pos].cmd = mail->msg.buf[BLE_MSG_CMD_POS];
        bleSelectData[pos].outtime = BLE_CONN_OUTTIME;
        ble_mux_send_msg(pos, mail);
      }
    }
  }
  else
  {
    LOG_E("BLE msg is err ,none Mac!!!!!!!!!!");
  }
  //分析出这条报文MAC
  //判断是否是新的MAC
  //判断是否睡眠报文
  //按机制发送

}


static void ble_uart_send_msg(void)
{
    rt_err_t result;
    bleMailDef *mail;

    result = rt_mb_recv(mcuTxMail, (rt_ubase_t *)&mail, 10);
    if(result == RT_EOK)
    {
      if(mail->msg.buf[1] == MCU_ADV_HEAD2)//广播主机的
      {
        int size;
        rt_kprintf("ADV%2d<<<",mail->msgLen);
        show_hex_string(mail->msg.buf, mail->msgLen);
        size =  rt_device_write(uartADV,0, mail->msg.buf, mail->msgLen);
        if(size != mail->msgLen)
        {
          LOG_E("ADV%2d<<<",mail->msgLen);
        }
      }
      else if(mail->msg.buf[1] == MCU_BLE_HEAD2)//蓝牙
      {
        ble_select_send_msg(mail);
      }

      rt_free(mail);
    }
    else
    {
      ble_selsct_outtime_process();//蓝牙主机超时
    }
}


static void ble_txMail_thread(void *parameter)
{
    while (1)
    {
        ble_uart_send_msg(); //发送扫描主机信息
        rt_thread_mdelay(2);
    }
}

static void ble_uart_recv_msg(rt_device_t uart)
{
    rt_uint8_t ch;
    rt_uint8_t *buf = RT_NULL;
    rt_uint8_t outTime = 100;
    rt_uint8_t pos = 0;
    rt_uint8_t recvLen = 0;

    buf = rt_calloc(1, ADV_MSG_BUF);
    RT_ASSERT(buf != RT_NULL);

    while(outTime--)
    {
        int size;
        size =  rt_device_read(uart,0, &ch, 1);//读取一个字节
        if(size == 1)
        {
            buf[pos++] = ch;
            if(pos == 2)
            {
                if(buf[0] != MCU_BLE_HEAD1 || buf[1] != MCU_BLE_HEAD2)
                {
                    LOG_E("BLE %s uart read error!buf[0]=%x buf[1]=%x",uart->parent.name,buf[0],buf[1]);
                    break;
                }
            }
            else if(pos ==3)
            {
              recvLen = buf[2];
              if(recvLen > sizeof(bleMsgDef))//长度错误
              {
                LOG_E("bleMsgDef recvLen is ERR");
                break;
              }
            }
            if((pos == recvLen)&&(recvLen != 0))//接收完成
            {
                rt_kprintf("BLE(%s)%2d>>>",uart->parent.name,recvLen);
                show_hex_string(buf, recvLen);
                bleMailDef *mail;

                mail = rt_calloc(1, sizeof(*mail));
                RT_ASSERT(mail);

                rt_memcpy(mail->msg.buf, buf, recvLen);
                mail->msgLen = recvLen;
                mail->outtime = NET_RX_MSG_OUTTIME;
                rt_err_t result = rt_mb_send(mcuRxMail, (rt_ubase_t)mail);
                if(result != RT_EOK)
                {
                  LOG_E("ble(%s) put mcuRxMail fail !!!!!!!!!!",uart->parent.name);
                  rt_free(mail);
                  break;
                }
                else
                {
                  break;
                }
            }

        }
        else
        {
          rt_thread_mdelay(5);
        }

    }
    rt_free(buf);
}

static void ble1_rxmsg_thread(void *parameter)
{
  LOG_I("ble1_rxmsg_thread");
  while (1)
  {
    ble_uart_recv_msg(uartBle1);
    ble_uart_recv_msg(uartBle2);
    rt_thread_mdelay(2);
  }
}
rt_device_t uart_hw_init(const char *name,rt_uint32_t Baud)
{
  rt_device_t uart;
  struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;

  uart = rt_device_find(name);
  if (uart == RT_NULL)
  {
      LOG_E("%s device not found!",name);
      return RT_NULL;
  }
  rt_err_t result = rt_device_open(uart, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
  if (result != RT_EOK)
  {
      LOG_E("%s device open failed!",name);
      return RT_NULL;
  }
  
  config.baud_rate = Baud;
  result = rt_device_control(uart, RT_DEVICE_CTRL_CONFIG, &config);
  if (result != RT_EOK)
  {
      LOG_E("%s device config failed!",name);
      return RT_NULL;
  }

  LOG_I("%s inti ok",name);
  return uart;
}


void adv_master_init(void)
{
    LOG_I("adv_master_init");

    uartADV = uart_hw_init(ADV_UART_NAME, BAUD_RATE_115200);
    RT_ASSERT(uartADV);

    uartBle1 = uart_hw_init(BLE1_UART_NAME, BAUD_RATE_115200);
    RT_ASSERT(uartBle1);

    uartBle2 = uart_hw_init(BLE2_UART_NAME, BAUD_RATE_115200);
    RT_ASSERT(uartBle2);

    mcuRxMail = rt_mb_create("MCUTX", 100, RT_IPC_FLAG_FIFO);
    RT_ASSERT(mcuRxMail);

    mcuTxMail = rt_mb_create("MCURX", 100, RT_IPC_FLAG_FIFO);
    RT_ASSERT(mcuTxMail);

    ble_select_init();


    rt_thread_t tid = rt_thread_create("adv_master", adv_master_thread, RT_NULL,
                                       2048, RT_THREAD_PRIORITY_MAX - 2, 20);
    if (tid != NULL)
        rt_thread_startup(tid);

    tid = rt_thread_create("advrx", adv_process_thread, RT_NULL,
                                       2048, RT_THREAD_PRIORITY_MAX - 2, 20);
    if (tid != NULL)
        rt_thread_startup(tid);
    tid = rt_thread_create("advtx", ble_txMail_thread, RT_NULL,
                                       2048, RT_THREAD_PRIORITY_MAX - 2, 20);
    if (tid != NULL)
        rt_thread_startup(tid);

    tid = rt_thread_create("blerx", ble1_rxmsg_thread, RT_NULL,
                                       2048, RT_THREAD_PRIORITY_MAX - 2, 20);
    if (tid != NULL)
        rt_thread_startup(tid);
    
}


void testBleCmd(int argc,char **argv)
{
  bleMailDef *mail;
  
  if(argc < 2)
  {
      rt_kprintf("Usage: %s <cmd>\n", argv[0]);
      return;
  }

  mail = rt_calloc(1, sizeof(*mail));
  RT_ASSERT(mail);

  if(argc == 2)
  {    
    mail->cmd = atoi(argv[1]);
    switch(mail->cmd)
    {
      case BLE_CMD_BOUNDDEV_ACK:
      {
        LOG_W("BLE_CMD_BOUNDDEV_ACK");
        mail->msgLen = sizeof(boundDevAckDef);
        mail->msg.proto.boudnDevAck.result = 0;
        break;
      }
      default:
      {
        LOG_W("None this cmd");
        break;
      }
    }
  }

  if(argc == 3)
  {
    mail->cmd = atoi(argv[1]);
    switch (mail->cmd)
    {
      case BLE_CMD_BOUNDDEV_REQ:
      {
        mail->msgLen = sizeof(bleBoundDevReqDef);
        mail->msg.proto.advSetModeAck.result = atoi(argv[2]);
        break;
      }
      case BLE_CMD_DEVSLEEP_REQ:
      {
        mail->msgLen = sizeof(bleDevSleepReqDef);
        mail->msg.proto.devSleepReq.sleep = atoi(argv[2]);
      }
      case BLE_CMD_DEVSLEEP_ACK:
      {
        mail->msgLen = sizeof(bleDevSleepAckDef);
        mail->msg.proto.devSleepAck.result = atoi(argv[2]);
      }
    }
  }
  
  mail->outtime = NET_RX_MSG_OUTTIME;
  mail->msg.proto.advReport.head[0] = MCU_BLE_HEAD1;
  mail->msg.proto.advReport.head[1] = MCU_BLE_HEAD2;
  mail->msg.proto.advReport.len = mail->msgLen;
  mail->msg.proto.advReport.cmd = mail->cmd;
  rt_memcpy(&(mail->msg.proto.advReport.ssid),"1233",4);
  rt_memcpy(&(mail->msg.proto.advReport.mac),"\x01\x01\x01\x01\x01\x01",6);
  rt_uint16_t crc = CRC16_MODBUS(mail->msg.buf,mail->msgLen-2);
  uint16_to_str(crc, &(mail->msg.buf[mail->msgLen-2]));
  show_hex_string(mail->msg.buf, mail->msgLen);
  rt_mb_send(mcuRxMail, (rt_ubase_t)mail);

}
MSH_CMD_EXPORT(testBleCmd,"测试蓝牙命令，命令，");


void sendADVCmd(int argc,char **argv)
{
  bleMailDef *mail;
  
  if(argc < 2)
  {
      rt_kprintf("Usage: %s <cmd>\n", argv[0]);
      return;
  }

  mail = rt_calloc(1, sizeof(*mail));
  RT_ASSERT(mail);

  if(argc == 2)
  {    
    mail->cmd = atoi(argv[1]);
    switch(mail->cmd)
    {
      case ADV_CMD_SET_MODE_ACK:
      {
        LOG_W("ADV_CMD_SET_MODE_ACK");
        mail->msgLen = sizeof(advSetModeAckDef);
        mail->msg.proto.advSetModeAck.result = 0;
        break;
      }
      default:
      {
        LOG_W("None this cmd");
        break;
      }
    }
  }

  if(argc == 3)
  {
    mail->cmd = atoi(argv[1]);
    switch (mail->cmd)
    {
      case ADV_CMD_SET_MODE_REQ:
      {
        LOG_W("ADV_CMD_SET_MODE_REQ");
        mail->msgLen = sizeof(advSetModeReqDef);
        mail->msg.proto.advSetModeReq.mode = (unsigned char)atoi(argv[1]);
        break;
      }
      default:
      {
        break;
      }
    }
  }
  
  mail->outtime = NET_RX_MSG_OUTTIME;
  mail->msg.proto.advReport.head[0] = MCU_ADV_HEAD1;
  mail->msg.proto.advReport.head[1] = MCU_ADV_HEAD2;
  mail->msg.proto.advReport.len = mail->msgLen;
  mail->msg.proto.advReport.cmd = mail->cmd;
  rt_memcpy(&(mail->msg.proto.advReport.ssid),"1233",4);
  rt_memcpy(&(mail->msg.proto.advReport.mac),"\x01\x01\x01\x01\x01\x01",6);
  rt_uint16_t crc = CRC16_MODBUS(mail->msg.buf,mail->msgLen-2);
  uint16_to_str(crc, &(mail->msg.buf[mail->msgLen-2]));
  show_hex_string(mail->msg.buf, mail->msgLen);
  rt_mb_send(mcuRxMail, (rt_ubase_t)mail);

}

MSH_CMD_EXPORT(sendADVCmd,"测试蓝牙广播接收报文");

